package model.bo;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;

import model.entidade.Empregado;
import model.entidade.Emprestimo;

public class EmprestimoBO {

	private static EmprestimoBO instancia;
	private static List<Emprestimo> listaEmprestimo;
	private static int emprestimoIncrementador = 0;
	private static ArrayList<Emprestimo> listaEmprestimoAInserir;

	/**
	 * Método executado para garantir a existência de apenas uma instância dessa classe (Singleton).
	 * 
	 * @return uma instância da classe EmpregadoBO 
	 * @author Zeno
	 * 
	 */
	public static EmprestimoBO getInstance() {
		if (instancia == null) {
			instancia = new EmprestimoBO();
		}
		listaEmprestimo= new ArrayList<Emprestimo>();
		
		return instancia;
	}


	private Emprestimo emprestimo;


	public Emprestimo consultar(int codigo) throws Exception {

		for (Emprestimo emprestimo: listaEmprestimoAInserir)
			if (emprestimo.getCodigo()==codigo)
				return emprestimo;

		return null;

	}

	/**
	 * Método executado para incluir os emprestimos na lista
	 * 
	 * @param emprestimo
	 * @throws Exception
	 * @author Arthur
	 * 
	 */
	public void incluir(Emprestimo emprestimo) throws Exception {		
		listaEmprestimo.add(emprestimo);
	}

	public void incluirLista(Emprestimo emprestimo) throws Exception {
	
		Emprestimo emprestimoIncluir = null;
		
		emprestimoIncluir= solicitar(emprestimo);
		
		if (emprestimoIncluir!=null)
			incluir(emprestimoIncluir);
		else
			throw new EmprestimoException("Impossivel incluir emprestimo");
		
	}

	public List<Emprestimo> listar() throws Exception {
		return listaEmprestimo;
	}

	

	/**
	 * Método executado para apresentar o Nome do empregado, o valor do empréstimo,
	 * de cada prestação e o valor total a pagar (soma das prestações).
	 * 
	 * 
	 * @param emprestimo do tipo Emprestimo
	 * @return imprime na tela cada uma das informações referentes ao impréstimo
	 * @author Wanessa, Arthur, Rúben
	 * @throws Exception 
	 * @throws EmprestimoException 
	 *
	 */

	public Emprestimo solicitar(Emprestimo emprestimo) throws EmprestimoException, Exception 
	{		

		Empregado empregado= EmpregadoBO.getInstance().consultarCpf(emprestimo.getCpfEmpregado());

		Emprestimo emprestimoAInserir= null;

		BigDecimal valorEmprestimoSolicitado = emprestimo.getValor();

		BigDecimal valorLimiteEmprestimo = calculaValorLimiteEmprestimoPeloSalario(empregado.getCpf());

		boolean temLimiteDeSalarioParaEmprestimo = verificaLimiteSalario(valorLimiteEmprestimo, emprestimo.getCpfEmpregado());
		boolean temLimiteParaOValorSolicitado = valorLimiteEmprestimo.compareTo(valorEmprestimoSolicitado)>=0;

		if (temLimiteDeSalarioParaEmprestimo && temLimiteParaOValorSolicitado){  

			emprestimoAInserir= new Emprestimo();	
			emprestimoAInserir.setEmpregado(empregado);
			emprestimoAInserir.setValorPorExtenso(valorEmprestimoSolicitado.toString());
			emprestimoAInserir.setNumPrestacoes(emprestimo.getNumPrestacoes());			
			emprestimoAInserir.setValorPrestacao(calculaValorPrestacao(emprestimo));
			emprestimoAInserir.setValorTotal(calculaValorTotalEmprestimo(emprestimo));
			

		}
		else{
			throw new EmprestimoException("O empregado nao pode obter o emprestimo.");
		}

		return emprestimoAInserir;
	}




	/**
	 * Método executado para verificar se o empréstimo está dentro do limite da porcentagem salarial
	 *
	 * @param String cpfEmpregado
	 * @return Booleano que indica o emprestimo está dentro do limite
	 * @author Rúben
	 *
	 */

	public Boolean verificaLimiteSalario( BigDecimal valorEmprestimo, String cpfEmpregado) throws EmprestimoException,Exception {

		BigDecimal limite;

		limite = calculaValorLimiteEmprestimoPeloSalario(cpfEmpregado);

		//verifica se o valor do empréstimo é maior que zero e menor que o limite relativo ao salário
		if ( (valorEmprestimo.compareTo(BigDecimal.valueOf(0)) >0) && (limite.compareTo(valorEmprestimo)>=0) )
		{

			return true;
		}
		else{

			throw new EmprestimoException("Limite de credito indisponivel.");
		}

	}

	public BigDecimal calculaValorLimiteEmprestimoPeloSalario(String cpfEmpregado) throws EmprestimoException, Exception{

		Empregado empregado = EmpregadoBO.getInstance().consultarCpf(cpfEmpregado);

		BigDecimal salario = empregado.getSalario();

		double pct_ = calculaPctLimiteEmprestimoSobreSalario(cpfEmpregado);

		BigDecimal pct= BigDecimal.valueOf(pct_);

		return pct.multiply(salario);

	}

	/**
	 * Método executado obter o limite do empréstimo de acordo com o salário
	 *
	 * @param String cpfEmpregado
	 * @return double que retorna a porcentagem limite do empréstimo
	 * @author Wanessa
	 *
	 */

	public double calculaPctLimiteEmprestimoSobreSalario(String cpfEmpregado) throws EmprestimoException,Exception {

		Empregado empregado = EmpregadoBO.getInstance().consultarCpf(cpfEmpregado);

		BigDecimal salario = empregado.getSalario();

		int idade = EmpregadoBO.getInstance().calculaIdade(empregado.getDataNascimento());

		Boolean sexo = empregado.getSexo();

		double limite = 0;

		if(sexo)
		{
			limite = verificaLimiteParaSalarioMasculino(salario, idade);
		}
		else 
		{
			limite = verificaLimiteParaSalarioFeminino(idade);
		}

		return limite;

	}

	private double verificaLimiteParaSalarioFeminino(int idade) {

		double limite = 0;

		if(idade>=21 && idade <=30){
			limite= 0.70;
		}
		else if (idade>= 31 && idade <= 44){
			limite = 0.50;
		}
		else if (idade>=45 && idade<= 61){
			limite = 0.35;
		}
		return limite;
	}

	private double verificaLimiteParaSalarioMasculino(BigDecimal salario,
			int idade) {

		double limite = 0;

		if(idade>= 21 && idade <= 35){
			limite = verificaSalaraioIntervaloZeroACincoMilAInfinito(salario);
		}
		else if(idade>=36 && idade <=45){
			limite = verificaSalaraioIntervaloZeroASeisMilAInfinito(salario);
		}
		else if(idade>=46 && idade<=65){
			limite= 0.30;
		}
		return limite;
	}

	private double verificaSalaraioIntervaloZeroASeisMilAInfinito(
			BigDecimal salario) {
		double limite;
		if(salario.compareTo(BigDecimal.valueOf(6000)) > 0){ 
			limite = 0.60;
		}
		else{
			limite =0.55;
		}
		return limite;
	}

	private double verificaSalaraioIntervaloZeroACincoMilAInfinito(
			BigDecimal salario) {
		double limite;
		if(salario.compareTo(BigDecimal.valueOf(5000)) > 0){
			limite = 0.75;
		}
		else{
			limite = 0.70;
		}
		return limite;
	}




	/**
	 * Método executado para verificar se os campos obrigatórios estão preenchidos.
	 *
	 * @param emprestimo do tipo Emprestimo
	 * @return Booleano que indica se estão preenchidos ou não
	 * @author Zeno
	 *
	 */
	public boolean verificaCamposObrigatorios(Emprestimo emprestimo) throws EmprestimoException {

		if ((!emprestimo.getCpfEmpregado().equals("")) && (emprestimo.getNumPrestacoes() != 0) && (emprestimo.getValor() != null)) {
			return true; 
		}

		throw new EmprestimoException("Os campos obrigatorios nao foram preenchidos.");

	}

	/**
	 * Método executado para verificar se o CPF entrado corresponde
	 * ao CPF de algum empregado previamente cadastrado.
	 *
	 * @param String cpf
	 * @return Booleano que indica se existe esse cpf ou não
	 * @author Zeno
	 *
	 */
	public boolean verificaCpfEmpregado(String cpf) throws EmprestimoException, Exception {

		List<Empregado> listaEmpregados = EmpregadoBO.getInstance().listar();

		for (int i = 0; i < listaEmpregados.size(); i++) {
			if (cpf.equals(listaEmpregados.get(i).getCpf())) {
				return true;
			}
		}

		throw new EmprestimoException("Nao ha nenhum empregado cadastrado com esse CPF.");

	}

	/**
	 * Método executado para calcular o valor total a ser pago
	 * pelo empregado, incluindo os juros.
	 * 
	 * @param Instância da classe emprestimo
	 * @return Valor total a ser pago
	 * @author Arthur
	 * @param numPrestacoes 
	 *
	 */

	public double getTaxaJuros(int numPrestacoes){

		double taxaJuros;
		if (1<=numPrestacoes && numPrestacoes<=3){
			taxaJuros=0.05;
		}
		else if (4<=numPrestacoes && numPrestacoes<=10){
			taxaJuros=0.065;
		}
		else if (10<numPrestacoes && numPrestacoes<=15){
			taxaJuros=0.08;
		}
		else{
			taxaJuros=0.1;
		}

		return taxaJuros;
	}

	public double calculaCFEmprestimo(Emprestimo emprestimo){

		double cf;
		int n = emprestimo.getNumPrestacoes();
		double i =getTaxaJuros(n);
		cf=i/(1-(1/(Math.pow((1+i),n))));
		return cf;
	}



	public BigDecimal calculaValorTotalEmprestimo(Emprestimo emprestimo){

		return calculaValorPrestacao(emprestimo).multiply(BigDecimal.valueOf(emprestimo.getNumPrestacoes()));
	}


	/**
	 * Método executado para calcular o valor mensal a ser pago
	 * pelo empregado, incluindo os juros, sobre o emprestimo retirado.
	 * 
	 * @param Instância da classe emprestimo
	 * @return Valor mensal a ser pago
	 * @author Arthur
	 *
	 */

	public BigDecimal calculaValorPrestacao(Emprestimo emprestimo){

		BigDecimal TaxaJ = new BigDecimal(calculaCFEmprestimo(emprestimo));

		return emprestimo.getValor().multiply(TaxaJ);

	}





}
